package com.anlogic.sdk.bootimage.model;

import com.anlogic.sdk.bootimage.model.options.EncryptionType;
import com.anlogic.sdk.utils.StringUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Path;

public class BifWriter implements IBifParseConstants {
	private static final Set<String> supportedKeys = new HashSet<>();

	static {
		supportedKeys.add("auth_params");
		supportedKeys.add("fsbl_config");
		supportedKeys.add("keysrc_encryption");
		supportedKeys.add("ppkfile");
		supportedKeys.add("pskfile");
		supportedKeys.add("spkfile");
		supportedKeys.add("spksignature");
		supportedKeys.add("sskfile");
		supportedKeys.add("udf_bh");
	}

	public static String converToString(BootGenModel model) {
		StringBuilder builder = new StringBuilder();
		builder.append(getComments(model) + "\n");
		builder.append("the_ROM_image:\n");
		builder.append("{\n");
		List<String> bootConfigOptions = new ArrayList<>();
		if (model.isQspiX1()) {
			bootConfigOptions.add("qspi_x1_only");
		}
		if (model.isMmcClk()) {
			bootConfigOptions.add("mmc_clk_sel");
		}
		if (model.isUseAuthentication()) {
			builder.append(convertToBifLine("ppkfile", model.getPpkFile()));
			builder.append(convertToBifLine("pskfile", model.getPskFile()));
			builder.append(convertToBifLine("spkfile", model.getSpkFile()));
			builder.append(convertToBifLine("sskfile", model.getSskFile()));
			if (!model.isGenSpkSig() && model.authKeyLegalityMode0()) {
				builder.append(convertToBifLine("spksignature", model.getSpkSignFile()));
			}
			List<String> authParamOptions = new ArrayList<>();
			String spkId = model.getSpkId();
			if (StringUtils.isNotEmpty(spkId)) {
				authParamOptions.add(createKeyValueField("spk_id", spkId));
				builder.append(convertToBifLine("auth_params", authParamOptions));
			}
			if (model.isBHAuth()) {
				bootConfigOptions.add("bh_auth_enable");
				bootConfigOptions.add(createKeyValueField("authentication", model.getAuthType().getId()));
			}
		}
		if (model.isUseEncryption()) {
			builder.append(convertToBifLine("keysrc_encryption", model.getMpSoCKeyStore().getId()));
		}
		if (!bootConfigOptions.isEmpty())
			builder.append(convertToBootConfigLine("boot_config", bootConfigOptions));
		String keyFile = model.getKeyFile();
		for (Partition partition : model.getPartitions()) {
			if (partition.getEncryptionType().equals(EncryptionType.AES) && partition.getAESKeyFile().isEmpty()) {
				partition.setAESKeyFile(keyFile);
			}
			if (partition.getEncryptionType().equals(EncryptionType.SM4) && partition.getSM4KeyFile().isEmpty()) {
				partition.setSM4KeyFile(keyFile);
			}
			builder.append(PartitionStringConverter.convertToString(partition));
		}
		builder.append("}");
		return builder.toString();
	}

	private static Object getComments(BootGenModel model) {
		StringBuilder builder = new StringBuilder();
		builder.append("//");
		List<String> fields = new ArrayList<>();
		fields.add(createKeyValueField("arch", model.getChipType().getId()));
		fields.add(createKeyValueField("format", model.getFormatType()));
		builder.append(convertToFieldsString(fields));
		return builder.toString();
	}

	private static String convertToBifLine(String key, List<String> fields) {
		String value = convertToFieldsString(fields);
		return convertToBifLine(key, value);
	}

	private static String convertToFieldsString(List<String> fields) {
		return StringUtils.getCharSeparatedString(fields, "; ").trim();
	}
	
	private static String convertToBootConfigLine(String key, List<String> fields) {
		String value = StringUtils.getCharSeparatedString(fields, ", ").trim();
		return convertToBifBraceLine(key, value);
	}

	private static String convertToBifBraceLine(String key, String value) {
		if (StringUtils.isEmpty(value))
			return "";
		String line = String.format("\t%s{%s}\n", new Object[] { key, value });
		return line;
	}
	
	private static String convertToBifLine(String key, String value) {
		if (StringUtils.isEmpty(value))
			return "";
		String line = String.format("\t[%s]%s\n", new Object[] { key, value });
		return line;
	}

	private static String createKeyValueField(String key, String value) {
		return String.valueOf(key) + " = " + value;
	}

	public static Set<String> getSupportedkeys() {
		return supportedKeys;
	}
	
	public static String createBifCommand(BootGenModel model) {
		String cmd = "";
		if (model.isGenAuthKeys()) {
			cmd += createGenerateAuthKeyCommand(model);
			cmd += " && ";
		}
		if (model.isGenSpkSig()) {
			cmd += createGenSpkSigCmd(model);
			cmd += " && ";
		}
		cmd += createNormalCommand(model);
		return cmd;
	}
	
	public static String createGenSpkSigCmd(BootGenModel model) {
		StringBuilder builder = new StringBuilder();
		builder.append("boot_gen ");
		builder.append(" -image " + (new Path(model.getBifFile())).lastSegment());
		builder.append(" -arch " + model.getChipType().getId());
		builder.append(" -spksignature " + model.getSpkSignFile());
		return builder.toString();
	}
	
	public static String createGenerateAuthKeyCommand(BootGenModel model) {
		StringBuilder builder = new StringBuilder();
		builder.append("boot_gen ");
		builder.append(" -image " + (new Path(model.getBifFile())).lastSegment());
		builder.append(" -arch " + model.getChipType().getId());
		builder.append(" -generate_keys " + model.getAuthType().getId());
		return builder.toString();
	}
	
	public static String createNormalCommand(BootGenModel model) {
		StringBuilder builder = new StringBuilder();
		String outputFilePath = model.getOutputFile();
		builder.append("boot_gen ");
		builder.append(" -image " + (new Path(model.getBifFile())).lastSegment());
		builder.append(" -arch " + model.getChipType().getId());
		String fillBytes = model.getFillBytes();
		if (fillBytes != null && !fillBytes.isEmpty()) {
			builder.append(" -fill " + fillBytes);
		}
		if (model.isSplit()) {
			String splitOption = String.format(" -split %s", new Object[] { model.getFormatType().toLowerCase() });
			builder.append(splitOption);
		} else {
			builder.append(" -o " + outputFilePath);
		}
		if (model.isOverwrite() || model.isSplit())
			builder.append(" -w on");
		return builder.toString();
	}
}
